// *********************************************************
// Ravi Mehra
// 904425258
// ravishi@vt.edu
// ECE 3574
// Homework 8
// 12/4/2009
// Implementation file for PrimeSearch that has function declarations
// *********************************************************

#include "primeClass.h"
#include "primeThread.h"
#include <QThread>

// Constructor
PrimeSearch::PrimeSearch() {
    // initialize vars
    m_FromVal = 0;
    m_ToVal = 0;
    m_CounterVal = 0;
    m_TotalFoundVal = 0;
    m_PrimeThread = new PrimeThread();
    m_Dead = false;

    // Set up and initialize application
    setupPrimeSearch(this);
    initializeInMainLogin();
}

// This function sets up all of the buttons, labels, entry boxes, etc
// Generated from Qt Designer
void PrimeSearch::setupPrimeSearch(QMainWindow *MainWindow)
{
    // Reorients main window
    MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
    MainWindow->resize(493, 598);

    // Create all widgets for the app
    centralwidget = new QWidget(MainWindow);
    centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
	
	// Create the prime question with the large font
    m_TitleQuestion = new QLabel(centralwidget);
    m_TitleQuestion->setObjectName(QString::fromUtf8("m_TitleQuestion"));
    m_TitleQuestion->setGeometry(QRect(40, 20, 411, 41));
    QFont font;
    font.setFamily(QString::fromUtf8("AlArabiya"));
    font.setPointSize(16);
    m_TitleQuestion->setFont(font);
	
	// Generate all the Labels
    m_FromLabel = new QLabel(centralwidget);
    m_FromLabel->setObjectName(QString::fromUtf8("m_FromLabel"));
    m_FromLabel->setGeometry(QRect(40, 70, 41, 18));
    m_ToLabel = new QLabel(centralwidget);
    m_ToLabel->setObjectName(QString::fromUtf8("m_ToLabel"));
    m_ToLabel->setGeometry(QRect(270, 70, 21, 18));
    m_CounterLabel = new QLabel(centralwidget);
    m_CounterLabel->setObjectName(QString::fromUtf8("m_CounterLabel"));
    m_CounterLabel->setGeometry(QRect(370, 200, 71, 16));
    m_TotalFoundLabel = new QLabel(centralwidget);
    m_TotalFoundLabel->setObjectName(QString::fromUtf8("m_TotalFoundLabel"));
    m_TotalFoundLabel->setGeometry(QRect(60, 460, 121, 20));
	
	// Generate all the entry boxes
    m_FromBox = new QLineEdit(centralwidget);
    m_FromBox->setObjectName(QString::fromUtf8("m_FromBox"));
    m_FromBox->setGeometry(QRect(80, 70, 151, 26));
    m_ToBox = new QLineEdit(centralwidget);
    m_ToBox->setObjectName(QString::fromUtf8("m_ToBox"));
    m_ToBox->setGeometry(QRect(290, 70, 151, 26));
    m_CounterBox = new QLineEdit(centralwidget);
    m_CounterBox->setObjectName(QString::fromUtf8("m_CounterBox"));
    m_CounterBox->setGeometry(QRect(340, 220, 113, 26));
    m_TotalFoundBox = new QLineEdit(centralwidget);
    m_TotalFoundBox->setObjectName(QString::fromUtf8("m_TotalFoundBox"));
    m_TotalFoundBox->setGeometry(QRect(190, 460, 151, 26));

	// Generate the progress bar and set to 0
    m_ProgressBar = new QProgressBar(centralwidget);
    m_ProgressBar->setObjectName(QString::fromUtf8("m_ProgressBar"));
    m_ProgressBar->setGeometry(QRect(20, 420, 451, 23));
    m_ProgressBar->setValue(0);

	// Generate the ListWidget to display the primes
    m_PrimesList = new QListWidget(centralwidget);
    m_PrimesList->setObjectName(QString::fromUtf8("m_PrimesList"));
    m_PrimesList->setGeometry(QRect(30, 120, 271, 281));
	
	// Generate all the buttons
    m_StartButton = new QPushButton(centralwidget);
    m_StartButton->setObjectName(QString::fromUtf8("m_StartButton"));
    m_StartButton->setGeometry(QRect(70, 510, 92, 28));
    m_StopButton = new QPushButton(centralwidget);
    m_StopButton->setObjectName(QString::fromUtf8("m_StopButton"));
    m_StopButton->setGeometry(QRect(190, 510, 92, 28));
    m_ExitButton = new QPushButton(centralwidget);
    m_ExitButton->setObjectName(QString::fromUtf8("m_ExitButton"));
    m_ExitButton->setGeometry(QRect(320, 510, 92, 28));
	
	// Generate all the file menu options
    MainWindow->setCentralWidget(centralwidget);
    menubar = new QMenuBar(MainWindow);
    menubar->setObjectName(QString::fromUtf8("menubar"));
    menubar->setGeometry(QRect(0, 0, 493, 25));
    menuFile = new QMenu(menubar);
    menuFile->setObjectName(QString::fromUtf8("menuFile"));
    MainWindow->setMenuBar(menubar);
    statusbar = new QStatusBar(MainWindow);
    statusbar->setObjectName(QString::fromUtf8("statusbar"));
    MainWindow->setStatusBar(statusbar);

    // Create all the menu items and add them to the menubar
    m_ActionStart = new QAction(MainWindow);
    m_ActionStart->setObjectName(QString::fromUtf8("m_ActionStart"));
    m_ActionStop = new QAction(MainWindow);
    m_ActionStop->setObjectName(QString::fromUtf8("m_ActionStop"));
    m_ActionExit = new QAction(MainWindow);
    m_ActionExit->setObjectName(QString::fromUtf8("m_ActionExit"));
    menubar->addAction(menuFile->menuAction());
    menuFile->addAction(m_ActionStart);
    menuFile->addAction(m_ActionStop);
    menuFile->addAction(m_ActionExit);

    // Name each label
    retranslatePrimeSearch(MainWindow);

    QMetaObject::connectSlotsByName(MainWindow);
}

// This function was exported from Qt Designer.  It translates all widget labels to provide other languages
void PrimeSearch::retranslatePrimeSearch(QMainWindow *MainWindow)
{
    // Change the names for the menu widgets
    MainWindow->setWindowTitle(QApplication::translate("MainWindow", "Prime Number Generator", 0, QApplication::UnicodeUTF8));
    m_ActionStart->setText(QApplication::translate("MainWindow", "Start", 0, QApplication::UnicodeUTF8));
    m_ActionStop->setText(QApplication::translate("MainWindow", "Stop", 0, QApplication::UnicodeUTF8));
    m_ActionExit->setText(QApplication::translate("MainWindow", "Exit", 0, QApplication::UnicodeUTF8));
    m_TitleQuestion->setText(QApplication::translate("MainWindow", "How many prime numbers are there?", 0, QApplication::UnicodeUTF8));
    m_FromLabel->setText(QApplication::translate("MainWindow", "From", 0, QApplication::UnicodeUTF8));
    m_ToLabel->setText(QApplication::translate("MainWindow", "To", 0, QApplication::UnicodeUTF8));
    m_CounterLabel->setText(QApplication::translate("MainWindow", "Counter", 0, QApplication::UnicodeUTF8));
    m_TotalFoundLabel->setText(QApplication::translate("MainWindow", "Total primes found", 0, QApplication::UnicodeUTF8));
    m_TotalFoundBox->setText(QApplication::translate("MainWindow", "", 0, QApplication::UnicodeUTF8));
    m_StartButton->setText(QApplication::translate("MainWindow", "Start", 0, QApplication::UnicodeUTF8));
    m_StopButton->setText(QApplication::translate("MainWindow", "Stop", 0, QApplication::UnicodeUTF8));
    m_ExitButton->setText(QApplication::translate("MainWindow", "Exit", 0, QApplication::UnicodeUTF8));
    menuFile->setTitle(QApplication::translate("MainWindow", "File", 0, QApplication::UnicodeUTF8));
}

// Initialize game in the main login panel and set up and clear certain variables
void PrimeSearch::initializeInMainLogin() {
    // Connect all of the push buttons and menu items to their appropriate slots
    connect(m_ActionExit, SIGNAL(triggered()), qApp, SLOT(quit()));
    qApp->connect(m_ExitButton, SIGNAL(clicked()), qApp, SLOT(quit()));
    connect(m_ActionStart, SIGNAL(triggered()), this, SLOT(start()));
    qApp->connect(m_StartButton, SIGNAL(clicked()), this, SLOT(start()));
    connect(m_ActionStop, SIGNAL(triggered()), this, SLOT(stop()));
    qApp->connect(m_StopButton, SIGNAL(clicked()), this, SLOT(stop()));
    
	// Connect the signals and slots between this and the prime thread
    connect (m_PrimeThread,  SIGNAL(returnedVal(int)), this, SLOT(addPrime(int)));
    connect (this,  SIGNAL(sendInputValues(int, int)), m_PrimeThread, SLOT(getInputValues(int, int)));
    
    // Set entry boxes values non edittable to user
    m_CounterBox->setReadOnly(1);
    m_TotalFoundBox->setReadOnly(1);
    
	// Set to blank
    m_TotalFoundBox->setText("");
    
    // Enable only certain menu items
    m_ActionStart->setEnabled(1);
    m_ActionStop->setEnabled(0);
    m_StartButton->setEnabled(1);
    m_StopButton->setEnabled(0);
}

// This slot is called when the thread returns a value
void PrimeSearch::addPrime(int returnedVal) {
    QTextStream cout(stdout);
	// If thread is already deemed to be terminated
    if (m_Dead == true) {
        return;
    }
    QString valString;
    m_CounterVal++;
	// If the current number was a prime
    if (returnedVal != -1) {
        m_PrimesList->addItem(valString.setNum(returnedVal));
        m_TotalFoundVal++;
    }
    m_CounterBox->setText(valString.setNum(m_TotalFoundVal));
	// Update the progress bar with how much it has finished
    m_ProgressBar->setValue(100 * (m_CounterVal + m_FromVal) / m_ToVal);
	// If it has returned all of the values, it should be finished
    if (m_CounterVal == (m_ToVal - m_FromVal) + 1) {
        m_TotalFoundBox->setText(valString.setNum(m_TotalFoundVal));
		// Enable only certain menu items
        m_ActionStart->setEnabled(1);
        m_ActionStop->setEnabled(0);
        m_StartButton->setEnabled(1);
        m_StopButton->setEnabled(0);
    }
	// Else it is still waiting to finish
    else {
        m_TotalFoundBox->setText("Waiting for answer ....");
    }
}

// This function is called when the start button is pushed
void PrimeSearch::start() {
    QTextStream cout(stdout);
    QString fromText, toText;
	// Get values from boxes as strings
    fromText = m_FromBox->text();
    toText = m_ToBox->text();
    bool ok1, ok2;
	// Convert the strings to ints
    m_FromVal = fromText.toInt(&ok1, 10);
    m_ToVal = toText.toInt(&ok2, 10);
	// Check to make sure the conversion did not fail
    if (ok1 == false || ok2 == false) {
        cout << "ERROR: From and To entries can only contain numbers" << endl;
        return;
    }
	// Check to make sure the end is larger or equal to the "From"
    if (m_FromVal > m_ToVal) {
        cout << "ERROR: From entry cannot be larger than the To entry" << endl;
        return;
    }
	// Clear the existing list
    m_PrimesList->clear();
	// Reset vars
    m_Dead = false;
    m_CounterVal = 0;
    m_TotalFoundVal = 0;
	// Enable only certain menu items
    m_ActionStart->setEnabled(0);
    m_ActionStop->setEnabled(1);
    m_StartButton->setEnabled(0);
    m_StopButton->setEnabled(1);
	// Send input variables to the thread
    emit sendInputValues(m_FromVal, m_ToVal);
	// Star the thread
    m_PrimeThread->start();
}

// This function is called when the stop button is pushed
void PrimeSearch::stop() {
    QTextStream cout(stdout);
	// Terminate the thread
    m_PrimeThread->terminate();
	// Declare it terminated
    m_Dead = true;
    m_TotalFoundBox->setText("Process stopped");
	// Enable only certain menu items
    m_ActionStart->setEnabled(1);
    m_ActionStop->setEnabled(0);
    m_StartButton->setEnabled(1);
    m_StopButton->setEnabled(0);
	// Reset vars
    m_CounterVal = 0;
    m_TotalFoundVal = 0;
}
